home *** CD-ROM | disk | FTP | other *** search
/ Software of the Month Club 2000 October / Software of the Month - Ultimate Collection Shareware 277.iso / pc / PROGRAMS / UTILITY / WINLINUX / DATA1.CAB / programs_-_kernel_source / SCRIPTS / MKDEP.C < prev    next >
C/C++ Source or Header  |  1999-09-17  |  10KB  |  506 lines

  1. /*
  2.  * Originally by Linus Torvalds.
  3.  * Smart CONFIG_* processing by Werner Almesberger, Michael Chastain.
  4.  *
  5.  * Usage: mkdep file ...
  6.  * 
  7.  * Read source files and output makefile dependency lines for them.
  8.  * I make simple dependency lines for #include <*.h> and #include "*.h".
  9.  * I also find instances of CONFIG_FOO and generate dependencies
  10.  *    like include/config/foo.h.
  11.  */
  12.  
  13. #include <ctype.h>
  14. #include <stdio.h>
  15. #include <stdlib.h>
  16. #include <string.h>
  17. #include <unistd.h>
  18.  
  19. #include <sys/fcntl.h>
  20. #include <sys/mman.h>
  21. #include <sys/stat.h>
  22. #include <sys/types.h>
  23.  
  24.  
  25.  
  26. char __depname[512] = "\n\t@touch ";
  27. #define depname (__depname+9)
  28. int hasdep;
  29.  
  30. struct path_struct {
  31.     int len;
  32.     char buffer[256-sizeof(int)];
  33. } path_array[2] = {
  34.     {  0, "" },
  35.     {  0, "" }
  36. };
  37.  
  38.  
  39.  
  40. /*
  41.  * This records all the configuration options seen.
  42.  * In perl this would be a hash, but here it's a long string
  43.  * of values separated by newlines.  This is simple and
  44.  * extremely fast.
  45.  */
  46. char * str_config  = NULL;
  47. int    size_config = 0;
  48. int    len_config  = 0;
  49.  
  50.  
  51.  
  52. /*
  53.  * Grow the configuration string to a desired length.
  54.  * Usually the first growth is plenty.
  55.  */
  56. void grow_config(int len)
  57. {
  58.     if (str_config == NULL) {
  59.         len_config  = 0;
  60.         size_config = 4096;
  61.         str_config  = malloc(4096);
  62.         if (str_config == NULL)
  63.             { perror("malloc"); exit(1); }
  64.     }
  65.  
  66.     while (len_config + len > size_config) {
  67.         str_config = realloc(str_config, size_config *= 2);
  68.         if (str_config == NULL)
  69.             { perror("malloc"); exit(1); }
  70.     }
  71. }
  72.  
  73.  
  74.  
  75. /*
  76.  * Lookup a value in the configuration string.
  77.  */
  78. int is_defined_config(const char * name, int len)
  79. {
  80.     const char * pconfig;
  81.     const char * plast = str_config + len_config - len;
  82.     for ( pconfig = str_config + 1; pconfig < plast; pconfig++ ) {
  83.         if (pconfig[ -1] == '\n'
  84.         &&  pconfig[len] == '\n'
  85.         &&  !memcmp(pconfig, name, len))
  86.             return 1;
  87.     }
  88.     return 0;
  89. }
  90.  
  91.  
  92.  
  93. /*
  94.  * Add a new value to the configuration string.
  95.  */
  96. void define_config(int convert, const char * name, int len)
  97. {
  98.     grow_config(len + 1);
  99.  
  100.     memcpy(str_config+len_config, name, len);
  101.  
  102.     if (convert) {
  103.         int i;
  104.         for (i = 0; i < len; i++) {
  105.             char c = str_config[len_config+i];
  106.             if (isupper(c)) c = tolower(c);
  107.             if (c == '_')   c = '/';
  108.             str_config[len_config+i] = c;
  109.         }
  110.     }
  111.  
  112.     len_config += len;
  113.     str_config[len_config++] = '\n';
  114. }
  115.  
  116.  
  117.  
  118. /*
  119.  * Clear the set of configuration strings.
  120.  */
  121. void clear_config(void)
  122. {
  123.     len_config = 0;
  124.     define_config(0, "", 0);
  125. }
  126.  
  127.  
  128.  
  129. /*
  130.  * Handle an #include line.
  131.  */
  132. void handle_include(int type, const char * name, int len)
  133. {
  134.     struct path_struct *path = path_array+type;
  135.  
  136.     if (len == 14 && !memcmp(name, "linux/config.h", len))
  137.         return;
  138.  
  139.     if (len >= 7 && !memcmp(name, "config/", 7))
  140.         define_config(0, name+7, len-7-2);
  141.  
  142.     memcpy(path->buffer+path->len, name, len);
  143.     path->buffer[path->len+len] = '\0';
  144.     if (access(path->buffer, F_OK) != 0)
  145.         return;
  146.  
  147.     if (!hasdep) {
  148.         hasdep = 1;
  149.         printf("%s:", depname);
  150.     }
  151.     printf(" \\\n   %s", path->buffer);
  152. }
  153.  
  154.  
  155.  
  156. /*
  157.  * Record the use of a CONFIG_* word.
  158.  */
  159. void use_config(const char * name, int len)
  160. {
  161.     char *pc;
  162.     int i;
  163.  
  164.     pc = path_array[0].buffer + path_array[0].len;
  165.     memcpy(pc, "config/", 7);
  166.     pc += 7;
  167.  
  168.     for (i = 0; i < len; i++) {
  169.         char c = name[i];
  170.         if (isupper(c)) c = tolower(c);
  171.         if (c == '_')   c = '/';
  172.         pc[i] = c;
  173.     }
  174.     pc[len] = '\0';
  175.  
  176.     if (is_defined_config(pc, len))
  177.         return;
  178.  
  179.     define_config(0, pc, len);
  180.  
  181.     if (!hasdep) {
  182.         hasdep = 1;
  183.         printf("%s: ", depname);
  184.     }
  185.     printf(" \\\n   $(wildcard %s.h)", path_array[0].buffer);
  186. }
  187.  
  188.  
  189.  
  190. /*
  191.  * Macros for stunningly fast map-based character access.
  192.  * __buf is a register which holds the current word of the input.
  193.  * Thus, there is one memory access per sizeof(unsigned long) characters.
  194.  */
  195.  
  196. #if defined(__alpha__) || defined(__i386__) || defined(__arm__)
  197. #define LE_MACHINE
  198. #endif
  199.  
  200. #ifdef LE_MACHINE
  201. #define next_byte(x) (x >>= 8)
  202. #define current ((unsigned char) __buf)
  203. #else
  204. #define next_byte(x) (x <<= 8)
  205. #define current (__buf >> 8*(sizeof(unsigned long)-1))
  206. #endif
  207.  
  208. #define GETNEXT { \
  209.     next_byte(__buf); \
  210.     if ((unsigned long) next % sizeof(unsigned long) == 0) { \
  211.         if (next >= end) \
  212.             break; \
  213.         __buf = * (unsigned long *) next; \
  214.     } \
  215.     next++; \
  216. }
  217.  
  218. /*
  219.  * State machine macros.
  220.  */
  221. #define CASE(c,label) if (current == c) goto label
  222. #define NOTCASE(c,label) if (current != c) goto label
  223.  
  224. /*
  225.  * Yet another state machine speedup.
  226.  */
  227. #define MAX2(a,b) ((a)>(b)?(a):(b))
  228. #define MIN2(a,b) ((a)<(b)?(a):(b))
  229. #define MAX6(a,b,c,d,e,f) (MAX2(a,MAX2(b,MAX2(c,MAX2(d,MAX2(e,f))))))
  230. #define MIN6(a,b,c,d,e,f) (MIN2(a,MIN2(b,MIN2(c,MIN2(d,MIN2(e,f))))))
  231.  
  232.  
  233.  
  234. /*
  235.  * The state machine looks for (approximately) these Perl regular expressions:
  236.  *
  237.  *    m|\/\*.*?\*\/|
  238.  *    m|'.*?'|
  239.  *    m|".*?"|
  240.  *    m|#\s*include\s*"(.*?)"|
  241.  *    m|#\s*include\s*<(.*?>"|
  242.  *    m|#\s*(?define|undef)\s*CONFIG_(\w*)|
  243.  *    m|(?!\w)CONFIG_|
  244.  *    m|__SMP__|
  245.  *
  246.  * About 98% of the CPU time is spent here, and most of that is in
  247.  * the 'start' paragraph.  Because the current characters are
  248.  * in a register, the start loop usually eats 4 or 8 characters
  249.  * per memory read.  The MAX6 and MIN6 tests dispose of most
  250.  * input characters with 1 or 2 comparisons.
  251.  */
  252. void state_machine(const char * map, const char * end)
  253. {
  254.     const char * next = map;
  255.     const char * map_dot;
  256.     unsigned long __buf = 0;
  257.  
  258.     for (;;) {
  259. start:
  260.     GETNEXT
  261. __start:
  262.     if (current > MAX6('/','\'','"','#','C','_')) goto start;
  263.     if (current < MIN6('/','\'','"','#','C','_')) goto start;
  264.     CASE('/',  slash);
  265.     CASE('\'', squote);
  266.     CASE('"',  dquote);
  267.     CASE('#',  pound);
  268.     CASE('C',  cee);
  269.     CASE('_',  underscore);
  270.     goto start;
  271.  
  272. /* / */
  273. slash:
  274.     GETNEXT
  275.     NOTCASE('*', __start);
  276. slash_star_dot_star:
  277.     GETNEXT
  278. __slash_star_dot_star:
  279.     NOTCASE('*', slash_star_dot_star);
  280.     GETNEXT
  281.     NOTCASE('/', __slash_star_dot_star);
  282.     goto start;
  283.  
  284. /* '.*?' */
  285. squote:
  286.     GETNEXT
  287.     CASE('\'', start);
  288.     NOTCASE('\\', squote);
  289.     GETNEXT
  290.     goto squote;
  291.  
  292. /* ".*?" */
  293. dquote:
  294.     GETNEXT
  295.     CASE('"', start);
  296.     NOTCASE('\\', dquote);
  297.     GETNEXT
  298.     goto dquote;
  299.  
  300. /* #\s* */
  301. pound:
  302.     GETNEXT
  303.     CASE(' ',  pound);
  304.     CASE('\t', pound);
  305.     CASE('i',  pound_i);
  306.     CASE('d',  pound_d);
  307.     CASE('u',  pound_u);
  308.     goto __start;
  309.  
  310. /* #\s*i */
  311. pound_i:
  312.     GETNEXT NOTCASE('n', __start);
  313.     GETNEXT NOTCASE('c', __start);
  314.     GETNEXT NOTCASE('l', __start);
  315.     GETNEXT NOTCASE('u', __start);
  316.     GETNEXT NOTCASE('d', __start);
  317.     GETNEXT NOTCASE('e', __start);
  318.     goto pound_include;
  319.  
  320. /* #\s*include\s* */
  321. pound_include:
  322.     GETNEXT
  323.     CASE(' ',  pound_include);
  324.     CASE('\t', pound_include);
  325.     map_dot = next;
  326.     CASE('"',  pound_include_dquote);
  327.     CASE('<',  pound_include_langle);
  328.     goto __start;
  329.  
  330. /* #\s*include\s*"(.*)" */
  331. pound_include_dquote:
  332.     GETNEXT
  333.     CASE('\n', start);
  334.     NOTCASE('"', pound_include_dquote);
  335.     handle_include(1, map_dot, next - map_dot - 1);
  336.     goto start;
  337.  
  338. /* #\s*include\s*<(.*)> */
  339. pound_include_langle:
  340.     GETNEXT
  341.     CASE('\n', start);
  342.     NOTCASE('>', pound_include_langle);
  343.     handle_include(0, map_dot, next - map_dot - 1);
  344.     goto start;
  345.  
  346. /* #\s*d */
  347. pound_d:
  348.     GETNEXT NOTCASE('e', __start);
  349.     GETNEXT NOTCASE('f', __start);
  350.     GETNEXT NOTCASE('i', __start);
  351.     GETNEXT NOTCASE('n', __start);
  352.     GETNEXT NOTCASE('e', __start);
  353.     goto pound_define_undef;
  354.  
  355. /* #\s*u */
  356. pound_u:
  357.     GETNEXT NOTCASE('n', __start);
  358.     GETNEXT NOTCASE('d', __start);
  359.     GETNEXT NOTCASE('e', __start);
  360.     GETNEXT NOTCASE('f', __start);
  361.     goto pound_define_undef;
  362.  
  363. /* #\s*(define|undef)\s*CONFIG_(\w*) */
  364. pound_define_undef:
  365.     GETNEXT
  366.     CASE(' ',  pound_define_undef);
  367.     CASE('\t', pound_define_undef);
  368.  
  369.             NOTCASE('C', __start);
  370.     GETNEXT NOTCASE('O', __start);
  371.     GETNEXT NOTCASE('N', __start);
  372.     GETNEXT NOTCASE('F', __start);
  373.     GETNEXT NOTCASE('I', __start);
  374.     GETNEXT NOTCASE('G', __start);
  375.     GETNEXT NOTCASE('_', __start);
  376.  
  377.     map_dot = next;
  378. pound_define_undef_CONFIG_word:
  379.     GETNEXT
  380.     if (isalnum(current) || current == '_')
  381.         goto pound_define_undef_CONFIG_word;
  382.     define_config(1, map_dot, next - map_dot - 1);
  383.     goto __start;
  384.  
  385. /* \<CONFIG_(\w*) */
  386. cee:
  387.     if (next >= map+2 && (isalnum(next[-2]) || next[-2] == '_'))
  388.         goto start;
  389.     GETNEXT NOTCASE('O', __start);
  390.     GETNEXT NOTCASE('N', __start);
  391.     GETNEXT NOTCASE('F', __start);
  392.     GETNEXT NOTCASE('I', __start);
  393.     GETNEXT NOTCASE('G', __start);
  394.     GETNEXT NOTCASE('_', __start);
  395.  
  396.     map_dot = next;
  397. cee_CONFIG_word:
  398.     GETNEXT
  399.     if (isalnum(current) || current == '_')
  400.         goto cee_CONFIG_word;
  401.     use_config(map_dot, next - map_dot - 1);
  402.     goto __start;
  403.  
  404. /* __SMP__ */
  405. underscore:
  406.     GETNEXT NOTCASE('_', __start);
  407.     GETNEXT NOTCASE('S', __start);
  408.     GETNEXT NOTCASE('M', __start);
  409.     GETNEXT NOTCASE('P', __start);
  410.     GETNEXT NOTCASE('_', __start);
  411.     GETNEXT NOTCASE('_', __start);
  412.     use_config("SMP", 3);
  413.     goto __start;
  414.  
  415.     }
  416. }
  417.  
  418.  
  419.  
  420. /*
  421.  * Generate dependencies for one file.
  422.  */
  423. void do_depend(const char * filename, const char * command)
  424. {
  425.     int mapsize;
  426.     int pagesizem1 = getpagesize()-1;
  427.     int fd;
  428.     struct stat st;
  429.     char * map;
  430.  
  431.     fd = open(filename, O_RDONLY);
  432.     if (fd < 0) {
  433.         perror(filename);
  434.         return;
  435.     }
  436.  
  437.     fstat(fd, &st);
  438.     if (st.st_size == 0) {
  439.         fprintf(stderr,"%s is empty\n",filename);
  440.         close(fd);
  441.         return;
  442.     }
  443.  
  444.     mapsize = st.st_size;
  445.     mapsize = (mapsize+pagesizem1) & ~pagesizem1;
  446.     map = mmap(NULL, mapsize, PROT_READ, MAP_PRIVATE, fd, 0);
  447.     if ((long) map == -1) {
  448.         perror("mkdep: mmap");
  449.         close(fd);
  450.         return;
  451.     }
  452.     if ((unsigned long) map % sizeof(unsigned long) != 0)
  453.     {
  454.         fprintf(stderr, "do_depend: map not aligned\n");
  455.         exit(1);
  456.     }
  457.  
  458.     hasdep = 0;
  459.     clear_config();
  460.     state_machine(map, map+st.st_size);
  461.     if (hasdep)
  462.         puts(command);
  463.  
  464.     munmap(map, mapsize);
  465.     close(fd);
  466. }
  467.  
  468.  
  469.  
  470. /*
  471.  * Generate dependencies for all files.
  472.  */
  473. int main(int argc, char **argv)
  474. {
  475.     int len;
  476.     char *hpath;
  477.  
  478.     hpath = getenv("HPATH");
  479.     if (!hpath) {
  480.         fputs("mkdep: HPATH not set in environment.  "
  481.               "Don't bypass the top level Makefile.\n", stderr);
  482.         return 1;
  483.     }
  484.     len = strlen(hpath);
  485.     memcpy(path_array[0].buffer, hpath, len);
  486.     if (len && hpath[len-1] != '/')
  487.         path_array[0].buffer[len++] = '/';
  488.     path_array[0].buffer[len] = '\0';
  489.     path_array[0].len = len;
  490.  
  491.     while (--argc > 0) {
  492.         const char * filename = *++argv;
  493.         const char * command  = __depname;
  494.         len = strlen(filename);
  495.         memcpy(depname, filename, len+1);
  496.         if (len > 2 && filename[len-2] == '.') {
  497.             if (filename[len-1] == 'c' || filename[len-1] == 'S') {
  498.                 depname[len-1] = 'o';
  499.                 command = "";
  500.             }
  501.         }
  502.         do_depend(filename, command);
  503.     }
  504.     return 0;
  505. }
  506.